package com.sh.business.service.facade;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sh.business.config.RabbitmqSender;
import com.sh.business.domain.*;
import com.sh.business.domain.dto.DelayMessageDto;
import com.sh.business.domain.dto.TransactionHistoryDto;
import com.sh.business.mapper.*;
import com.sh.common.core.constant.Constants;
import com.sh.common.core.enums.*;
import com.sh.common.core.utils.*;
import com.sh.common.json.utils.JsonUtils;
import com.sh.common.redis.utils.RedisUtils;
import com.sh.system.service.ISysConfigService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.util.ArrayList;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

import static com.sh.common.core.constant.SZPNConstants.*;

@Slf4j
@Service
public class TransactionServiceFacade {


    @Resource
    private ISysConfigService iSysConfigService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserInvestMapper investMapper;
    @Resource
    private UserWithdrawalMapper userWithdrawalMapper;
    @Resource
    private RabbitmqSender rabbitmqSender;
    @Resource
    private UserFoundServiceFacade userFoundServiceFacade;
    @Resource
    private MiningMapper miningMapper;
    @Resource
    private SzpnConfigMapper szpnConfigMapper;
    @Resource
    private UserRepurchaseMapper userRepurchaseMapper;

    private final String TX_FROM = "from";
    private final String TX_TO = "to";
    private final String TX_VALUE = "value";
    /**
     * 固定去除最后18位字符。（截取16位，除以100，然后四舍五入。）
     */
    private final Integer REMOVE_NUM = 16;
    /**
     * 数组长度
     */
    private final Integer PARAMS_LENGTH = 3;
    /**
     * 交易状态
     */
    private final String RECEIPT_STATUS = "1";

    /**
     * USDT
     */
    private final String TOKEN_SYMBOL = "USDT";

    /**
     * USDT 合约地址
     */
    private final String BSC_USDT_CONTRACT_ADDRESS = "0x55d398326f99059ff775485246999027b3197955";


    /**
     * 校验投资交易事件状态
     */
    public void checkTransactionByHash(DelayMessageDto delayMessageDto) {



        String transaction = BlockChainUtils.getDecodeTransactionByHash(delayMessageDto.getTxHash());
        log.info("checkTransactionByHash:{}", transaction);
        Dict transactionData = JsonUtils.parseMap(transaction);


        if (ObjectUtil.isNotNull(transactionData) && RECEIPT_STATUS.equals(transactionData.getStr("receipt_status"))) {

            String fromAddress = "";
            String toAddress = "";
            String value = "";
            String blockTime = transactionData.getByPath("logs[0].block_timestamp");

            for (int i = 0; i < PARAMS_LENGTH; i++) {
                if (TX_FROM.equals(transactionData.getByPath("logs[0].decoded_event.params[" + i + "].name"))) {
                    fromAddress = transactionData.getByPath("logs[0].decoded_event.params[" + i + "].value");
                    continue;
                }
                if (TX_TO.equals(transactionData.getByPath("logs[0].decoded_event.params[" + i + "].name"))) {
                    toAddress = transactionData.getByPath("logs[0].decoded_event.params[" + i + "].value");
                    continue;
                }
                if (TX_VALUE.equals(transactionData.getByPath("logs[0].decoded_event.params[" + i + "].name"))) {
                    value = transactionData.getByPath("logs[0].decoded_event.params[" + i + "].value");
                    continue;
                }
            }
            // 去除16位后的数字为真实交易数量
            value = value.substring(0, value.length() - REMOVE_NUM);

            // 金额除以100，四舍五入 todo:金额问题
            BigDecimal amount = new BigDecimal(value).divide(new BigDecimal("100")).setScale(4, RoundingMode.HALF_UP);

            if (MessageTypeEnum.INVEST.getCode().equals(delayMessageDto.getType())) {

                // 平台收款地址
                String TO_ADDRESS = iSysConfigService.selectConfigByKey("bsc.toAddress");

                UserInvest userInvest = investMapper.queryByTxHash(delayMessageDto.getTxHash());
                //Mining mining = miningMapper.queryByPrice(userInvest.getAmount());
                User user = userMapper.selectById(userInvest.getUserId());

                UserInvest update = new UserInvest();
                update.setId(userInvest.getId());

                // 判定结果交易是否到账，且结果正确
                if (amount.subtract(userInvest.getAmount()).abs().compareTo(BigDecimal.ONE) <= 0
                    && StringUtils.equalsIgnoreCase(fromAddress, userInvest.getFromAddress())
                    && StringUtils.equalsIgnoreCase(toAddress, TO_ADDRESS)
                    && StringUtils.equalsIgnoreCase(BSC_USDT_CONTRACT_ADDRESS, transactionData.getStr("to_address"))
                    && DateUtils.isWithin24Hours(blockTime)) {

                    log.info("tx:{},已到账", userInvest.getTxHash());

                    update.setToAddress(toAddress);
                    update.setStatus(TransferStatusEnum.CONFIRM_RECEIPT.getCode());
                    update.setNotifyData(transaction);

                    int ok = investMapper.updateById(update);
                    if (ok == 0) {
                        log.error("更新失败，重复操作:" + delayMessageDto.getTxHash());
                    } else {

                        // 激活链接及节点
                        activeAndNode(user, userInvest);

                        // 获得空投及算力
                        userFoundServiceFacade.airdropAndComputility(userInvest);

                        userFoundServiceFacade.changeUserFound(user.getUserId(), UserFoundEnum.SELF_ACHIEVEMENT, TransferFlagEnum.TRANSFER_IN, amount);


                        // 发送异步处理消息
                        rabbitmqSender.sendCallBackMsg(delayMessageDto.getTxHash());
                    }

                } else {

                    log.error("tx:" + delayMessageDto.getTxHash() + ",数据异常，账户或金额错误");

                    update.setStatus(TransferStatusEnum.CONFIRM_ERROR.getCode());
                    update.setNotifyData(transaction);
                    update.setRemark("数据异常，账户或金额错误");

                    investMapper.updateById(update);
                }

            } else if (MessageTypeEnum.REPURCHASE.getCode().equals(delayMessageDto.getType())) {

                // 平台收款地址
                String TO_ADDRESS = iSysConfigService.selectConfigByKey("bsc.repurchase.toAddress");

                UserRepurchase userRepurchase = userRepurchaseMapper.queryByTxHash(delayMessageDto.getTxHash());
                //Mining mining = miningMapper.queryByPrice(userInvest.getAmount());
                User user = userMapper.selectById(userRepurchase.getUserId());

                UserRepurchase update = new UserRepurchase();
                update.setId(userRepurchase.getId());

                if (amount.subtract(userRepurchase.getAmount()).abs().compareTo(BigDecimal.ONE) <= 0
                        && StringUtils.equalsIgnoreCase(fromAddress, userRepurchase.getFromAddress())
                        && StringUtils.equalsIgnoreCase(toAddress, TO_ADDRESS)
                        && StringUtils.equalsIgnoreCase(BSC_USDT_CONTRACT_ADDRESS, transactionData.getStr("to_address"))
                        && DateUtils.isWithin24Hours(blockTime)) {

                    log.info("tx:{},已到账", userRepurchase.getTxHash());

                    update.setToAddress(toAddress);
                    update.setStatus(TransferStatusEnum.CONFIRM_RECEIPT.getCode());
                    update.setNotifyData(transaction);

                    int ok = userRepurchaseMapper.updateById(update);
                    if (ok == 0) {
                        log.error("更新失败，重复操作:" + delayMessageDto.getTxHash());
                    } else {

                        // 增加用户复购u
                        userFoundServiceFacade.modifyUserFound(userRepurchase.getUserId(),
                                userRepurchase.getOrderSn(),
                                userRepurchase.getTxHash(),
                                UserFoundEnum.REPURCHASE_USDT,
                                TransferFlagEnum.TRANSFER_IN,
                                userRepurchase.getAmount(),
                                TransferDescEnum.RECHARGE.getCode().toString(),
                                null);
                    }

                } else {

                    log.error("tx:" + delayMessageDto.getTxHash() + ",数据异常，账户或金额错误");

                    update.setStatus(TransferStatusEnum.CONFIRM_ERROR.getCode());
                    update.setNotifyData(transaction);
                    update.setRemark("数据异常，账户或金额错误");

                    userRepurchaseMapper.updateById(update);
                }
            } else if (MessageTypeEnum.WITHDRAW.getCode().equals(delayMessageDto.getType())) {

                // 平台收款地址
                String TO_ADDRESS = iSysConfigService.selectConfigByKey("bsc.toAddress");

                UserWithdrawal userWithdrawal = userWithdrawalMapper.queryByTxHash(delayMessageDto.getTxHash());

                UserWithdrawal update = new UserWithdrawal();
                update.setId(userWithdrawal.getId());

                // 提现，这里是到账账户和fromAddress
                if (StringUtils.equalsIgnoreCase(toAddress, userWithdrawal.getFromAddress())) {

                    log.info("tx:" + userWithdrawal.getTxHash() + ",已到账");
                    update.setTransferTime(DateUtils.getNowDate());
                    update.setNotifyData(transaction);
                    update.setStatus(WithdrawStatusEnum.CONFIRM_RECEIPT.getCode());
                    userWithdrawalMapper.updateById(update);

                } else {
                    log.error("tx:" + delayMessageDto.getTxHash() + ",数据异常，账户或金额错误");
                    update.setTransferTime(DateUtils.getNowDate());
                    update.setNotifyData(transaction);
                    update.setStatus(WithdrawStatusEnum.CONFIRM_ERROR.getCode());
                    update.setRemark("数据异常，账户或金额错误");

                    userWithdrawalMapper.updateById(update);
                    // todo: 是否需要退回？
                }
            }

        } else {
            // 未查询到结果，继续查询 1天
            int range = 24;
            // 1天内未到账，继续查询
            if (DateUtils.differentHourByMillisecond(delayMessageDto.getCreateTime(), DateUtils.getNowDate()) < range) {
                // 继续查询 - 60秒
                rabbitmqSender.sendTtlMsg(delayMessageDto, null);
            }
        }

    }

    /**
     * 激活链接及节点
     * @param user
     * @param userInvest
     */
    public void activeAndNode(User user, UserInvest userInvest) {
        // 激活用户
        if (!user.getIsActive()) {
            User updateUser = new User();
            updateUser.setUserId(user.getUserId());
            updateUser.setIsActive(true);
            userMapper.updateById(updateUser);
        }
        Map<Integer, SzpnConfig> szpnConfigMap = StreamUtils.toMap(szpnConfigMapper.selectList(), SzpnConfig::getUserLevel, Function.identity());
        // 是否是大额投资，如果是则直接获得节点身份标识
        if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V11.getCode()).getInvestAmount()) >= 0 && userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V12.getCode()).getInvestAmount()) < 0) {
            User updateUser = new User();
            updateUser.setUserId(user.getUserId());
            updateUser.setIsNode(true);
            if (user.getNodeFlag() < SzpnUserLevelEnum.V11.getCode()) {
                updateUser.setNodeFlag(SzpnUserLevelEnum.V11.getCode());
            }
            userMapper.updateById(updateUser);
        } else if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V12.getCode()).getInvestAmount()) >= 0 && userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V13.getCode()).getInvestAmount()) < 0) {
            User updateUser = new User();
            updateUser.setUserId(user.getUserId());
            updateUser.setIsNode(true);
            if (user.getNodeFlag() < SzpnUserLevelEnum.V12.getCode()) {
                updateUser.setNodeFlag(SzpnUserLevelEnum.V12.getCode());
            }
            userMapper.updateById(updateUser);
        } else if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V13.getCode()).getInvestAmount()) >= 0 && userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V14.getCode()).getInvestAmount()) < 0) {
            User updateUser = new User();
            updateUser.setUserId(user.getUserId());
            updateUser.setIsNode(true);
            if (user.getNodeFlag() < SzpnUserLevelEnum.V13.getCode()) {
                updateUser.setNodeFlag(SzpnUserLevelEnum.V13.getCode());
            }
            userMapper.updateById(updateUser);
        } else if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V14.getCode()).getInvestAmount()) >= 0 && userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V15.getCode()).getInvestAmount()) < 0) {
            User updateUser = new User();
            updateUser.setUserId(user.getUserId());
            updateUser.setIsNode(true);
            if (user.getNodeFlag() < SzpnUserLevelEnum.V14.getCode()) {
                updateUser.setNodeFlag(SzpnUserLevelEnum.V14.getCode());
            }
            userMapper.updateById(updateUser);
        } else if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V15.getCode()).getInvestAmount()) >= 0 ) {
            User updateUser = new User();
            updateUser.setUserId(user.getUserId());
            updateUser.setIsNode(true);
            if (user.getNodeFlag() < SzpnUserLevelEnum.V15.getCode()) {
                updateUser.setNodeFlag(SzpnUserLevelEnum.V15.getCode());
            }
            userMapper.updateById(updateUser);
        }
    }

    /**
     * 临时处理
     * @param delayMessageDto
     *//*
    public void checkTransactionByHashHandlezzz(DelayMessageDto delayMessageDto) {

        // 平台收款地址
        String TO_ADDRESS = iSysConfigService.selectConfigByKey("bsc.toAddress");

        String transaction = BlockChainUtils.getDecodeTransactionByHash(delayMessageDto.getTxHash());
        log.info("checkTransactionByHash:{}", transaction);
        Dict transactionData = JsonUtils.parseMap(transaction);


        if (ObjectUtil.isNotNull(transactionData) && RECEIPT_STATUS.equals(transactionData.getStr("receipt_status"))) {

            String fromAddress = "";
            String toAddress = "";
            String value = "";
            String blockTime = transactionData.getByPath("logs[0].block_timestamp");

            for (int i = 0; i < PARAMS_LENGTH; i++) {
                if (TX_FROM.equals(transactionData.getByPath("logs[0].decoded_event.params[" + i + "].name"))) {
                    fromAddress = transactionData.getByPath("logs[0].decoded_event.params[" + i + "].value");
                    continue;
                }
                if (TX_TO.equals(transactionData.getByPath("logs[0].decoded_event.params[" + i + "].name"))) {
                    toAddress = transactionData.getByPath("logs[0].decoded_event.params[" + i + "].value");
                    continue;
                }
                if (TX_VALUE.equals(transactionData.getByPath("logs[0].decoded_event.params[" + i + "].name"))) {
                    value = transactionData.getByPath("logs[0].decoded_event.params[" + i + "].value");
                    continue;
                }
            }
            // 去除16位后的数字为真实交易数量
            value = value.substring(0, value.length() - REMOVE_NUM);

            // 金额除以100，四舍五入 todo:金额问题
            BigDecimal amount = new BigDecimal(value).divide(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP);

            if (MessageTypeEnum.INVEST.getCode().equals(delayMessageDto.getType())) {

                UserInvest userInvest = investMapper.queryByTxHash(delayMessageDto.getTxHash());
                //Mining mining = miningMapper.queryByPrice(userInvest.getAmount());
                User user = userMapper.selectById(userInvest.getUserId());

                UserInvest update = new UserInvest();
                update.setId(userInvest.getId());

                // 判定结果交易是否到账，且结果正确
                if (amount.compareTo(userInvest.getAmount()) == 0
                    && StringUtils.equalsIgnoreCase(fromAddress, userInvest.getFromAddress())
                    && StringUtils.equalsIgnoreCase(toAddress, TO_ADDRESS)
                    && StringUtils.equalsIgnoreCase(BSC_USDT_CONTRACT_ADDRESS, transactionData.getStr("to_address"))
                    && DateUtils.isWithin24Hours(blockTime)) {

                    log.info("tx:{},已到账", userInvest.getTxHash());

                    update.setStatus(TransferStatusEnum.CONFIRM_RECEIPT.getCode());
                    update.setNotifyData(transaction);

                    int ok = investMapper.updateById(update);
                    if (ok == 0) {
                        log.error("更新失败，重复操作:" + delayMessageDto.getTxHash());
                    } else {
                        // 激活用户
                        if (!user.getIsActive()) {
                            User updateUser = new User();
                            updateUser.setUserId(user.getUserId());
                            updateUser.setIsActive(true);
                            userMapper.updateById(updateUser);
                        }
                        // 是否是大额投资，如果是则直接获得节点身份标识
                        if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V11.getCode()).getInvestAmount()) >= 0 && userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V12.getCode()).getInvestAmount()) < 0) {
                            User updateUser = new User();
                            updateUser.setUserId(user.getUserId());
                            updateUser.setIsNode(true);
                            if (user.getNodeFlag() < SzpnUserLevelEnum.V11.getCode()) {
                                updateUser.setNodeFlag(SzpnUserLevelEnum.V11.getCode());
                            }
                            userMapper.updateById(updateUser);
                        } else if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V12.getCode()).getInvestAmount()) >= 0 && userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V13.getCode()).getInvestAmount()) < 0) {
                            User updateUser = new User();
                            updateUser.setUserId(user.getUserId());
                            updateUser.setIsNode(true);
                            if (user.getNodeFlag() < SzpnUserLevelEnum.V12.getCode()) {
                                updateUser.setNodeFlag(SzpnUserLevelEnum.V12.getCode());
                            }
                            userMapper.updateById(updateUser);
                        } else if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V13.getCode()).getInvestAmount()) >= 0 && userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V14.getCode()).getInvestAmount()) < 0) {
                            User updateUser = new User();
                            updateUser.setUserId(user.getUserId());
                            updateUser.setIsNode(true);
                            if (user.getNodeFlag() < SzpnUserLevelEnum.V13.getCode()) {
                                updateUser.setNodeFlag(SzpnUserLevelEnum.V13.getCode());
                            }
                            userMapper.updateById(updateUser);
                        } else if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V14.getCode()).getInvestAmount()) >= 0 && userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V15.getCode()).getInvestAmount()) < 0) {
                            User updateUser = new User();
                            updateUser.setUserId(user.getUserId());
                            updateUser.setIsNode(true);
                            if (user.getNodeFlag() < SzpnUserLevelEnum.V14.getCode()) {
                                updateUser.setNodeFlag(SzpnUserLevelEnum.V14.getCode());
                            }
                            userMapper.updateById(updateUser);
                        } else if (userInvest.getAmount().compareTo(szpnConfigMap.get(SzpnUserLevelEnum.V15.getCode()).getInvestAmount()) >= 0 ) {
                            User updateUser = new User();
                            updateUser.setUserId(user.getUserId());
                            updateUser.setIsNode(true);
                            if (user.getNodeFlag() < SzpnUserLevelEnum.V15.getCode()) {
                                updateUser.setNodeFlag(SzpnUserLevelEnum.V15.getCode());
                            }
                            userMapper.updateById(updateUser);
                        }

                        // 获得空投及算力
                        userFoundServiceFacade.airdropAndComputility(userInvest);

                        userFoundServiceFacade.changeUserFound(user.getUserId(), UserFoundEnum.SELF_ACHIEVEMENT, TransferFlagEnum.TRANSFER_IN, amount);


                        // 发送异步处理消息
                        //rabbitmqSender.sendCallBackMsg(delayMessageDto.getTxHash());
                    }

                } else {

                    log.error("tx:" + delayMessageDto.getTxHash() + ",数据异常，账户或金额错误");

                    update.setStatus(TransferStatusEnum.CONFIRM_ERROR.getCode());
                    update.setNotifyData(transaction);
                    update.setRemark("数据异常，账户或金额错误");

                    investMapper.updateById(update);
                }

            } else if (MessageTypeEnum.WITHDRAW.getCode().equals(delayMessageDto.getType())) {

                UserWithdrawal userWithdrawal = userWithdrawalMapper.queryByTxHash(delayMessageDto.getTxHash());

                UserWithdrawal update = new UserWithdrawal();
                update.setId(userWithdrawal.getId());

                // 提现，这里是到账账户和fromAddress
                if (StringUtils.equalsIgnoreCase(toAddress, userWithdrawal.getFromAddress())) {

                    log.info("tx:" + userWithdrawal.getTxHash() + ",已到账");
                    update.setTransferTime(DateUtils.getNowDate());
                    update.setNotifyData(transaction);
                    update.setStatus(WithdrawStatusEnum.CONFIRM_RECEIPT.getCode());
                    userWithdrawalMapper.updateById(update);

                } else {
                    log.error("tx:" + delayMessageDto.getTxHash() + ",数据异常，账户或金额错误");
                    update.setTransferTime(DateUtils.getNowDate());
                    update.setNotifyData(transaction);
                    update.setStatus(WithdrawStatusEnum.CONFIRM_ERROR.getCode());
                    update.setRemark("数据异常，账户或金额错误");

                    userWithdrawalMapper.updateById(update);
                    // todo: 是否需要退回？
                }
            }

        } else {
            // 未查询到结果，继续查询 1天
            int range = 24;
            // 1天内未到账，继续查询
            if (DateUtils.differentHourByMillisecond(delayMessageDto.getCreateTime(), DateUtils.getNowDate()) < range) {
                // 继续查询 - 60秒
                rabbitmqSender.sendTtlMsg(delayMessageDto, null);
            }
        }

    }*/

    /**
     * 校验投资交易事件状态
     */
    /*public void checkTransactionByHash(DelayMessageDto delayMessageDto) {

        // 平台收款地址
        String TO_ADDRESS = iSysConfigService.selectConfigByKey("bsc.toAddress");

        String transaction = BlockChainUtils.getDecodeTransactionByHash(delayMessageDto.getTxHash());
        Dict transactionData = JsonUtils.parseMap(transaction);


        if (ObjectUtil.isNotNull(transactionData) && RECEIPT_STATUS.equals(transactionData.getStr("receipt_status"))) {

            String fromAddress = "";
            String toAddress = "";
            String value = "";
            String blockTime = transactionData.getByPath("logs[0].block_timestamp");

            for (int i = 0; i < PARAMS_LENGTH; i++) {
                if (TX_FROM.equals(transactionData.getByPath("logs[0].decoded_event.params[" + i + "].name"))) {
                    fromAddress = transactionData.getByPath("logs[0].decoded_event.params[" + i + "].value");
                    continue;
                }
                if (TX_TO.equals(transactionData.getByPath("logs[0].decoded_event.params[" + i + "].name"))) {
                    toAddress = transactionData.getByPath("logs[0].decoded_event.params[" + i + "].value");
                    continue;
                }
                if (TX_VALUE.equals(transactionData.getByPath("logs[0].decoded_event.params[" + i + "].name"))) {
                    value = transactionData.getByPath("logs[0].decoded_event.params[" + i + "].value");
                    continue;
                }
            }
            // 去除16位后的数字为真实交易数量
            value = value.substring(0, value.length() - REMOVE_NUM);

            // 金额除以100，四舍五入 todo:金额问题
            BigDecimal amount = new BigDecimal(value).divide(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP);

            if (MessageTypeEnum.INVEST.getCode().equals(delayMessageDto.getType())) {

                UserInvest userInvest = investMapper.queryByTxHash(delayMessageDto.getTxHash());
                Mining mining = miningMapper.queryByPrice(userInvest.getAmount());
                User user = userMapper.selectById(userInvest.getUserId());

                UserInvest update = new UserInvest();
                update.setId(userInvest.getId());

                // 判定结果交易是否到账，且结果正确
                if (ObjectUtil.isNotNull(mining)
                    && amount.compareTo(userInvest.getAmount()) == 0
                    && StringUtils.equalsIgnoreCase(fromAddress, userInvest.getFromAddress())
                    && StringUtils.equalsIgnoreCase(toAddress, TO_ADDRESS)
                    && StringUtils.equalsIgnoreCase(BSC_USDT_CONTRACT_ADDRESS, transactionData.getStr("to_address"))
                    && DateUtils.isWithin24Hours(blockTime)) {

                    log.info("tx:{},已到账", userInvest.getTxHash());

                    update.setStatus(TransferStatusEnum.CONFIRM_RECEIPT.getCode());
                    update.setNotifyData(transaction);

                    int ok = investMapper.updateById(update);
                    if (ok == 0) {
                        log.error("更新失败，重复操作:" + delayMessageDto.getTxHash());
                    } else {
                        // 激活用户
                        if (!user.getIsActive()) {
                            User updateUser = new User();
                            updateUser.setUserId(user.getUserId());
                            updateUser.setIsActive(true);
                            userMapper.updateById(updateUser);
                        }

                        // 奖励算力
                        userFoundServiceFacade.modifyUserFound(userInvest.getUserId(),
                            userInvest.getOrderSn(),
                            delayMessageDto.getTxHash(),
                            UserFoundEnum.COMPUTILITY,
                            TransferFlagEnum.TRANSFER_IN,
                            mining.getComputility(),
                            TransferDescEnum.PURCHASE_MINING.getCode().toString(),
                            null);

                        userFoundServiceFacade.changeUserFound(user.getUserId(), UserFoundEnum.SELF_ACHIEVEMENT, TransferFlagEnum.TRANSFER_IN, amount);


                        // 发送异步处理消息
                        rabbitmqSender.sendCallBackMsg(delayMessageDto.getTxHash());
                    }

                } else {

                    log.error("tx:" + delayMessageDto.getTxHash() + ",数据异常，账户或金额错误");

                    update.setStatus(TransferStatusEnum.CONFIRM_ERROR.getCode());
                    update.setNotifyData(transaction);
                    update.setRemark("数据异常，账户或金额错误");

                    investMapper.updateById(update);
                }

            } else if (MessageTypeEnum.WITHDRAW.getCode().equals(delayMessageDto.getType())) {

                UserWithdrawal userWithdrawal = userWithdrawalMapper.queryByTxHash(delayMessageDto.getTxHash());

                UserWithdrawal update = new UserWithdrawal();
                update.setId(userWithdrawal.getId());

                // 提现，这里是到账账户和fromAddress
                if (StringUtils.equalsIgnoreCase(toAddress, userWithdrawal.getFromAddress())) {

                    log.info("tx:" + userWithdrawal.getTxHash() + ",已到账");
                    update.setTransferTime(DateUtils.getNowDate());
                    update.setNotifyData(transaction);
                    update.setStatus(WithdrawStatusEnum.CONFIRM_RECEIPT.getCode());
                    userWithdrawalMapper.updateById(update);

                } else {
                    log.error("tx:" + delayMessageDto.getTxHash() + ",数据异常，账户或金额错误");
                    update.setTransferTime(DateUtils.getNowDate());
                    update.setNotifyData(transaction);
                    update.setStatus(WithdrawStatusEnum.CONFIRM_ERROR.getCode());
                    update.setRemark("数据异常，账户或金额错误");

                    userWithdrawalMapper.updateById(update);
                    // todo: 是否需要退回？
                }
            }

        } else {
            // 未查询到结果，继续查询 1天
            int range = 24;
            // 1天内未到账，继续查询
            if (DateUtils.differentHourByMillisecond(delayMessageDto.getCreateTime(), DateUtils.getNowDate()) < range) {
                // 继续查询 - 60秒
                rabbitmqSender.sendTtlMsg(delayMessageDto, null);
            }
        }

    }*/


    /**
     * 定时查询，是否有遗漏的充值交易 - usdt充值
     */
    public void handleWalletTransactionHistory() {
        // 平台校验地址
        String toAddress = iSysConfigService.selectConfigByKey("bsc.toAddress");
        String history = BlockChainUtils.getWalletTransactionHistory(toAddress);

        JSONObject entries = JSONUtil.parseObj(history);

        List<TransactionHistoryDto> result = JsonUtils.parseArray(entries.getStr("result"), TransactionHistoryDto.class);

        log.info("result:{}", result);
        for (TransactionHistoryDto transactionHistoryDto : result) {
            if (CollUtil.isEmpty(transactionHistoryDto.getErc20_transfers())) {
                continue;
            }

            boolean exists = investMapper.exists(Wrappers.<UserInvest>lambdaQuery().eq(UserInvest::getTxHash, transactionHistoryDto.getHash()));

            if (!exists
                && RECEIPT_STATUS.equals(transactionHistoryDto.getReceipt_status())
                && CollUtil.isNotEmpty(transactionHistoryDto.getErc20_transfers())
                && TOKEN_SYMBOL.equalsIgnoreCase(transactionHistoryDto.getErc20_transfers().get(0).getToken_symbol())
                && StringUtils.equalsIgnoreCase(BSC_USDT_CONTRACT_ADDRESS, transactionHistoryDto.getErc20_transfers().get(0).getAddress())
                && toAddress.equalsIgnoreCase(transactionHistoryDto.getErc20_transfers().get(0).getTo_address())) {

                String fromAddress = transactionHistoryDto.getErc20_transfers().get(0).getFrom_address();
                BigDecimal amount = Convert.toBigDecimal(transactionHistoryDto.getErc20_transfers().get(0).getValue_formatted()).setScale(0, RoundingMode.HALF_DOWN);
                //Mining mining = miningMapper.queryByPrice(amount);

                User user = userMapper.queryByWalletAddress(fromAddress);
                if (ObjectUtil.isNotNull(user)) {
                    // 保存遗漏充值信息
                    UserInvest invest = new UserInvest();
                    invest.setUserId(user.getUserId());
                    invest.setOrderSn(OrderSnUtil.generateOrderSn(OrderTypeEnum.TZ));
                    invest.setAmount(Convert.toBigDecimal(transactionHistoryDto.getErc20_transfers().get(0).getValue_formatted()));
                    invest.setPurchaseAmount(invest.getAmount());
                    invest.setTxHash(transactionHistoryDto.getHash());
                    invest.setStatus(TransferStatusEnum.CONFIRM_RECEIPT.getCode());
                    invest.setTransferTime(DateUtils.getNowDate());
                    invest.setFromAddress(transactionHistoryDto.getErc20_transfers().get(0).getFrom_address());
                    invest.setToAddress(toAddress);
                    invest.setNotifyData(JsonUtils.toJsonString(transactionHistoryDto));
                    invest.setRemark("遗漏充值记录");

                    investMapper.insert(invest);

                    // 激活链接及节点
                    activeAndNode(user, invest);

                    // 获得空投及算力
                    userFoundServiceFacade.airdropAndComputility(invest);

                    userFoundServiceFacade.changeUserFound(user.getUserId(), UserFoundEnum.SELF_ACHIEVEMENT, TransferFlagEnum.TRANSFER_IN, amount);

                    // 发送异步处理消息
                    rabbitmqSender.sendCallBackMsg(invest.getTxHash());
                }
            }
        }

    }

    public void handleError() {
        List<UserInvest> userInvestList = investMapper.selectList(Wrappers.<UserInvest>lambdaQuery().isNotNull(UserInvest::getRemark));
        userInvestList.forEach(userInvest -> {
            userFoundServiceFacade.changeUserFound(userInvest.getUserId(), UserFoundEnum.SELF_ACHIEVEMENT, TransferFlagEnum.TRANSFER_IN, userInvest.getAmount());

            rabbitmqSender.sendCallBackMsg(userInvest.getTxHash());
        });
    }


    /**
     * 查询scroll代币价格
     */
    public BigDecimal queryScrollPrice() {
        if (RedisUtils.hasKey("scroll_price_key")) {
            return RedisUtils.getCacheObject("scroll_price_key");
        }
        String transaction = BlockChainUtils.queryScrollPrice();
        Dict transactionData = JsonUtils.parseMap(transaction);

        String lastPrice = transactionData.getByPath("data[0].lastPrice");

        BigDecimal price = Convert.toBigDecimal(lastPrice).setScale(6, RoundingMode.DOWN);
        RedisUtils.setCacheObject("scroll_price_key", price, Duration.ofMinutes(1));
        return price;
    }



}
